package com.example.birthday_getway.config;

import com.auth0.jwt.interfaces.Claim;
import com.example.birthday_getway.utlis.JwtUtil;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.Collections;
import java.util.Map;

public class JwtWebFilter implements WebFilter {

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
    // 1. 放行OPTIONS请求
    if (exchange.getRequest().getMethod() == HttpMethod.OPTIONS) {
      return chain.filter(exchange);
    }
    String path = exchange.getRequest().getPath().value();
    System.out.println("Request path: " + exchange.getRequest().getPath());
    System.out.println("Request method: " + exchange.getRequest().getMethod());
    // 2. 放行公开路径
    if (path.startsWith("/api/auth") || path.equals("/rate")) {
      System.out.println("公开路径");
      return chain.filter(exchange);
    }

    // 3. 获取Token
    String header = exchange.getRequest().getHeaders().getFirst("Authorization");
    if (header == null || !header.startsWith("Bearer ")) {
      return sendErrorResponse(
          exchange, "Missing or invalid Authorization header", HttpStatus.UNAUTHORIZED);
    }

    String token = header.substring(7);

    // 4. 验证并解析Token（使用响应式方式包装阻塞操作）
    return Mono.fromCallable(() -> JwtUtil.getClaims(token))
        .subscribeOn(Schedulers.boundedElastic()) // 在弹性线程池执行阻塞操作
        .flatMap(
            claimsOpt -> {
              if (claimsOpt.isEmpty()) {
                return sendErrorResponse(exchange, "Invalid token", HttpStatus.UNAUTHORIZED);
              }

              Map<String, Claim> claims = claimsOpt.get();
              Claim uidClaim = claims.get("uid");

              if (uidClaim == null) {
                return sendErrorResponse(
                    exchange, "Missing user identifier", HttpStatus.UNAUTHORIZED);
              }

              String uid = uidClaim.asString();

              // 5. 创建认证对象并设置安全上下文
              Authentication authentication =
                  new UsernamePasswordAuthenticationToken(uid, null, Collections.emptyList());

              SecurityContextImpl securityContext = new SecurityContextImpl(authentication);

              return chain
                  .filter(exchange)
                  .contextWrite(
                      ReactiveSecurityContextHolder.withSecurityContext(
                          Mono.just(securityContext)));
            })
        .onErrorResume(
            e -> sendErrorResponse(exchange, "Token verification failed", HttpStatus.UNAUTHORIZED));
  }

  private Mono<Void> sendErrorResponse(
      ServerWebExchange exchange, String message, HttpStatus status) {
    exchange.getResponse().setStatusCode(status);
    return exchange
        .getResponse()
        .writeWith(
            Mono.just(exchange.getResponse().bufferFactory().wrap(message.getBytes()))
                .then(Mono.empty()));
  }
}
